package com.lhkj.ct.base.utils;

import cn.hutool.core.collection.CollectionUtil;
import com.lhkj.ct.base.model.IBaseTree;
import com.lhkj.ct.base.model.ITreeConverter;
import com.lhkj.ct.base.model.Tree;
import org.apache.commons.collections.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 *     树级机构工具类
 * </p>
 */
public class TreeUtil implements Serializable {

    /**
     * 构建树级数据
     * @param data      数据集合
     * @param <T>       父级id数据类型
     */
    public static <D extends IBaseTree<T> & Tree<D>, T> List<D> builderTree(List<D> data) {
        if (null == data) {
            return new ArrayList<>();
        }
        // 收集父id
        Set<T> parentIds = data.stream()
                .map(IBaseTree::getParentId)
                .collect(Collectors.toSet());

        // 收集所有菜单id
        Set<T> menuIds = data.stream()
                .map(IBaseTree::getId)
                .collect(Collectors.toSet());

        // 求差集，得到 parentIds 中 menuIds 没有的元素
        Collection<T> rootIds = CollectionUtils.subtract(parentIds, menuIds);

        // 组装树级结构数据
        List<D> list = new ArrayList<>();
        for (T rootId : rootIds) {
            list.addAll(recur(rootId, data)); // 递归
        }
        return list;
    }

    protected static <D extends IBaseTree<T> & Tree<D>, T> List<D> recur(T parentId, List<D> list) {
        return CollectionUtil.emptyIfNull(list)
                .stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .peek(entity -> {
                    List<D> children = recur(entity.getId(), list);
                    entity.setChildren(children);
                }).collect(Collectors.toList());
    }

    /**
     * 构建树级数据
     * @param data      数据集合
     * @param convert   转换类 S->R
     * @param <S>       源数据类
     * @param <T>       父级id数据类型
     * @param <R>       目标数据类
     * @param <C>       转换器
     */
    public static <S extends IBaseTree<T>, T, R extends Tree<R>, C extends ITreeConverter<S, R>>  List<R> builderTree(List<S> data, C convert) {
        // 收集父id
        Set<T> parentIds = data.stream()
                .map(IBaseTree::getParentId)
                .collect(Collectors.toSet());

        // 收集所有菜单id
        Set<T> menuIds = data.stream()
                .map(IBaseTree::getId)
                .collect(Collectors.toSet());

        // 求差集，得到 parentIds 中 menuIds 没有的元素
        List<T> rootIds = CollectionUtil.subtractToList(parentIds, menuIds);

        // 组装树级结构数据
        List<R> list = new ArrayList<>();
        for (T rootId : rootIds) {
            list.addAll(recur(rootId, data, convert)); // 递归
        }
        return list;
    }

    protected static <S extends IBaseTree<T>, R extends Tree<R>, T, C extends ITreeConverter<S, R>> List<R> recur(T parentId, List<S> list, C convert) {
        return CollectionUtil.emptyIfNull(list)
                .stream()
                .filter(s -> s.getParentId().equals(parentId))
                .map(entity -> {
                    R r = convert.convert(entity);
                    List<R> children = recur(entity.getId(), list, convert);
                    r.setChildren(children);
                    return r;
                }).collect(Collectors.toList());
    }

}
